package ssm.spring.ioc.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

/**
 * description: java配置类，替代xml配置文件
     1. 完全注解开发
     2. `@Configuration` 指定一个类为配置类，可以添加配置注解，替代 spring.xml 配置文件。
     3. `@ComponentScan(value = {"包路径1","包路径2"})` 配置包扫描路径，替代`context:component-scan`标签。
     4. `@PropertySource("classpath:配置文件地址")`读取外部配置，替代 `context:property-placeholder`标签。
     5. `@Value(${})` 获取外部配置文件参数对属性赋值，可以用于变量，也可用于方法形参。
     6. `@Bean` 注释方法，将方法创建的组件保存到IOC容器，用于将第三方组件实例化，对应一个bean标签。
     7. `@Bean` 方法返回类型为组件类型，方法名为组件名，方法体可以自定义实现过程。
     8. `@Bean(name = "")` 可以指定bean名称
     9. `@Bean(initMethod = "", destroyMethod = "")` 实现周期方法 PostConstruct/PreDestroy
     10. `@Scope()` 默认是单例模式
     11. 引用其他Bean组件时，可以通过调用方法名、形参传入方式从IOC容器中直接获取
 */

@ComponentScan(value = {"ssm.spring.ioc.config","ssm.spring.ioc_01"})
@PropertySource("classpath:jdbc.properties")
@Configuration
public class JavaConfiguration {

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    // TODO: @Bean引用第三方组件注入IOC容器
    @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON)
    @Bean(name = "ergouzi")
    public DruidDataSource dataSource1(){
        //实现具体的实例化过程
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    //TODO: @Bean属性initMethod/destroyMethod实现周期方法 PostConstruct/PreDestroy
    @Bean(initMethod = "init")
    public JavaConfigurationA init() {
        return new JavaConfigurationA();
    }

    @Bean(destroyMethod = "cleanup")
    public JavaConfigurationB cleanup() {
        return new JavaConfigurationB();
    }

    @Bean(name = "lvdandan")
    public DruidDataSource dataSource2(){
        //实现具体的实例化过程
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    /**
     * TODO：引用其他Bean组件
     * 1. 被引用的组件同样通过 @Bean 注解注入时，可以通过调用 @Bean 标识的方法从IOC容器获取组件
     * 2. 直接通过形参变量引入，要求被引用的组件必须已注入IOC容器，形参名和Bean名称相同
     */
    @Bean
    public JdbcTemplate jdbcTemplate(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //方案1： 如果其他组件也是@Bean方法，可以直接调用方法名，从ioc容器获取组件
        jdbcTemplate.setDataSource(dataSource1());
        return jdbcTemplate;
    }

    @Bean
    public JdbcTemplate jdbcTemplate1(DataSource lvdandan, DataSource ergouzi){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //方案2： 形参列表声明想要的组件类型，可以是多个
        jdbcTemplate.setDataSource(lvdandan);
        return jdbcTemplate;
    }

}
